<!DOCTYPE html>
<html>
  <head>
    <title>Go编译器定制简介</title>
    <meta charset='utf-8'>
    <script>
      var notesEnabled =  false ;
    </script>
    <script src='static/slides.js'></script>

    

    <script>
      
      if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
        var _gaq = _gaq || [];
        _gaq.push(["_setAccount", "UA-11222381-6"]);
        _gaq.push(["b._setAccount", "UA-49880327-6"]);
        window.trackPageview = function() {
          _gaq.push(["_trackPageview", location.pathname+location.hash]);
          _gaq.push(["b._trackPageview", location.pathname+location.hash]);
        };
        window.trackPageview();
        window.trackEvent = function(category, action, opt_label, opt_value, opt_noninteraction) {
          _gaq.push(["_trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
          _gaq.push(["b._trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
        };
      }
    </script>
  </head>

  <body style='display: none'>

    <section class='slides layout-widescreen'>

      <article>
        <h1>Go编译器定制简介</h1>
        
        
        
          <div class="presenter">
            
  
  <p>
    chai2010
  </p>
  

          </div>
        
          <div class="presenter">
            
  
  <p>
    
  </p>
  

          </div>
        
      </article>

  
  
      <article >
      
        <h3>自我介绍(chai2010)</h3>
        <ul>
<li>Go代码贡献者(<a href="https://github.com/golang/go/commits?author=chai2010" target="_blank" rel="noopener">golang</a>, <a href="https://github.com/golang/image/commits?author=chai2010" target="_blank" rel="noopener">go.image</a>)</li>
<li>蚂蚁集团从事云原生、蚂蚁链DSL语言设计和研发工作(<a href="https://github.com/wa-lang/ugo-compiler-book/blob/master/jobs.md" target="_blank" rel="noopener">招贤纳士</a>)</li>
<li><a href="https://github.com/wa-lang/ugo-compiler-book" target="_blank" rel="noopener">《µGo语言实现(从头开发一个迷你Go语言编译器)》</a> 作者</li>
<li><a href="https://github.com/chai2010/go-ast-book" target="_blank" rel="noopener">《Go语法树入门(出版名:Go语言定制指南)》</a> 作者</li>
<li><a href="https://github.com/chai2010/advanced-go-programming-book" target="_blank" rel="noopener">《Go语言高级编程》</a> 作者</li>
</ul>

<div class="image">
  <img src="go-compiler-intro/images/chai2010.png">
</div>

      
      <span class="pagenumber">2</span>
      </article>
  
  
  
      <article >
      
        <h3>我的图书(原创)</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/mybooks-01.png" height="580" width="800">
</div>

      
      <span class="pagenumber">3</span>
      </article>
  
  
  
      <article >
      
        <h3>我的图书(翻译)</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/mybooks-02.png">
</div>

      
      <span class="pagenumber">4</span>
      </article>
  
  
  
      <article >
      
        <h2>主题大纲</h2>
      
      <span class="pagenumber">5</span>
      </article>
  
  
  
      <article >
      
        <h3>主题大纲</h3>
        <ul>
<li>最简编译器</li>
<li>编译器后门八卦</li>
<li>Go和Rust的选择</li>
<li>Go衍生的语言</li>
<li>Go语法树</li>
<li>Go类型系统</li>
<li>SSA和LLVM</li>
<li>µGo案例</li>
<li>参考链接</li>
</ul>

      
      <span class="pagenumber">6</span>
      </article>
  
  
  
      <article >
      
        <h2>最简编译器</h2>
      
      <span class="pagenumber">7</span>
      </article>
  
  
  
      <article >
      
        <h3>编译器是什么</h3>
        <ul>
<li>编译器是一种精确的翻译程序</li>
<li>编译器输入的是数据序列, 输出的也是数据序列</li>
<li>编译器作为可执行程序可用于 AOT 翻译, 类似 <code>gcc</code> 命令</li>
<li>编译器也可以是一个函数, 用于 JIT 运行时翻译, 或者包装为 AOT 翻译命令</li>
<li>编译器一般是某种编程语言的翻译程序, 因此也就包含了编程语言的外延</li>
<li>现代编程语言不仅仅是翻译, 还有内置的运行时调度</li>
<li>编译器可以很复杂, 甚至可以内置 OS ...</li>
<li>编译器也可以很简单...</li>
</ul>

      
      <span class="pagenumber">8</span>
      </article>
  
  
  
      <article >
      
        <h3>人肉编译器</h3>
        <p>将一个整数编译为一个程序, 程序的返回值返回这个整数值</p>
<p>比如 <code>42</code> 翻译为以下的 C 语言程序:</p>

  <div class="code" >
<pre><span num="1">int main() {</span>
<span num="2">    <b>return 42;</b></span>
<span num="3">}</span>
</pre>
</div>
<p>也可以翻译为以下的 X86 汇编程序:</p>

  <div class="code" >
<pre><span num="1">.intel_syntax noprefix</span>
<span num="2">.globl _main</span>
<span num="3"></span>
<span num="4">_main:</span>
<span num="5">    <b>mov rax, 42 ;</b></span>
<span num="6">    ret</span>
</pre>
</div>
<p>也可以翻译为 LLVM 跨平台的汇编程序:</p>

  <div class="code" >
<pre><span num="1">define i32 @main() {</span>
<span num="2">    <b>ret i32 42 ;</b></span>
<span num="3">}</span>
</pre>
</div>

      
      <span class="pagenumber">9</span>
      </article>
  
  
  
      <article >
      
        <h3>Go程序替代人肉编译器</h3>
        <p>Go语言重新实现如下人肉编译器:</p>

  <div class="code" >
<pre><span num="14">func main() {</span>
<span num="15">    code, _ := io.ReadAll(os.Stdin)</span>
<span num="16">    <b>compile(string(code))</b></span>
<span num="17">}</span>
<span num="18"></span>
<span num="19">func compile(code string) {</span>
<span num="20">    <b>output := fmt.Sprintf(tmpl, code)</b></span>
<span num="21">    os.WriteFile(&#34;a.out.ll&#34;, []byte(output), 0666)</span>
<span num="22">    <b>exec.Command(&#34;clang&#34;, &#34;-o&#34;, &#34;a.out&#34;, &#34;a.out.ll&#34;).Run()</b></span>
<span num="23">}</span>
<span num="24"></span>
<span num="25">const tmpl = `</span>
<span num="26">define i32 @main() {</span>
<span num="27">    ret i32 %v</span>
<span num="28">}</span>
<span num="29">`</span>
</pre>
</div>
<p>编译 <code>echo 123 | go run main.go</code>, 执行 <code>./a.out</code>, 看结果 <code>echo $?</code></p>

      
      <span class="pagenumber">10</span>
      </article>
  
  
  
      <article >
      
        <h3>挑战: 继续前进一小步</h3>
        <ul>
<li>输入的数字变为支持加/减/乘/除法和小括弧的表达式(词法+语法解析)</li>
<li>输出 X86 汇编时如何处理多个中间结果?</li>
<li>如何简化优先级的处理?</li>
</ul>

      
      <span class="pagenumber">11</span>
      </article>
  
  
  
      <article >
      
        <h2>编译器后门八卦</h2>
      
      <span class="pagenumber">12</span>
      </article>
  
  
  
      <article >
      
        <h3>Reflections on Trusting Trust - 01 - 自重写程序</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/02-trust1.jpg" height="500" width="850">
</div>
<figcaption><code>s</code> 是从最后一个 <code>0</code> 到结尾的内容, 第1个 printf 打印 <code>s</code> 数组, 第2个打印后面部分</figcaption>
      
      <span class="pagenumber">13</span>
      </article>
  
  
  
      <article >
      
        <h3>Reflections on Trusting Trust - 02 - 鸡和蛋问题</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/02-trust2.jpg" height="500" width="850">
</div>
<figcaption>C编译器为了支持转义的自举过程</figcaption>
      
      <span class="pagenumber">14</span>
      </article>
  
  
  
      <article >
      
        <h3>Reflections on Trusting Trust - 03 - 潜伏的后门</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/02-trust3.jpg" height="500" width="850">
</div>
<figcaption>Ken 在C编译器植入后门后擦除记录, 同时在UNIX保留伪装的后门代码</figcaption>
      
      <span class="pagenumber">15</span>
      </article>
  
  
  
      <article >
      
        <h3>更多的自重写代码</h3>
        <p>可能是最短的C自重写代码:</p>

  <div class="code" >
<pre><span num="1">main(a){printf(a=&#34;main(a){printf(a=%c%s%c,34,a,34);}&#34;,34,a,34);}</span>
</pre>
</div>
<p><a href="https://research.swtch.com/zip" target="_blank" rel="noopener">rsc</a> 给了Go的版本(Go已经自举, 大家可以放心用了):</p>

  <div class="code" >
<pre><span num="1">package main</span>
<span num="2"></span>
<span num="3">import &#34;fmt&#34;</span>
<span num="4"></span>
<span num="5">func main() {</span>
<span num="6">    <b>fmt.Printf(&#34;%s%c%s%c\n&#34;, q, 0x60, q, 0x60)</b></span>
<span num="7">}</span>
<span num="8"></span>
<span num="9">var q = `package main</span>
<span num="10"></span>
<span num="11">import &#34;fmt&#34;</span>
<span num="12"></span>
<span num="13">func main() {</span>
<span num="14">    <b>fmt.Printf(&#34;%s%c%s%c\n&#34;, q, 0x60, q, 0x60)</b></span>
<span num="15">}</span>
<span num="16"></span>
<span num="17">var q = `</span>
</pre>
</div>

      
      <span class="pagenumber">16</span>
      </article>
  
  
  
      <article >
      
        <h2>Go和Rust的选择</h2>
      
      <span class="pagenumber">17</span>
      </article>
  
  
  
      <article >
      
        <h3>Go 开发的编译器</h3>
        <ul>
<li><a href="https://github.com/topics/compiler?l=Go" target="_blank" rel="noopener">https://github.com/topics/compiler?l=Go</a></li>
</ul>
<hr>
<ul>
<li>Go语法衍生: <a href="https://github.com/tinygo-org/tinygo" target="_blank" rel="noopener">TinyGo 9.1K</a>, <a href="https://github.com/goplus/gop" target="_blank" rel="noopener">Go+ 7.9K</a>, <a href="https://github.com/cuelang/cue" target="_blank" rel="noopener">CUE 3.2K</a></li>
</ul>
<hr>
<ul>
<li><a href="https://github.com/hashicorp/terraform" target="_blank" rel="noopener">Terraform</a> 30.6K Star</li>
<li><a href="https://github.com/evanw/esbuild" target="_blank" rel="noopener">esbuild</a> 29.5K Star</li>
</ul>
<hr>
<ul>
<li><a href="https://github.com/google/grumpy" target="_blank" rel="noopener">Google/Grumpy</a> 10.4K Star: Python 翻译到 Go</li>
<li><a href="https://github.com/google/skylark" target="_blank" rel="noopener">Google/SkyLark</a> 1.2K Star: Python 子集</li>
<li><a href="https://github.com/google/go-jsonnet" target="_blank" rel="noopener">Google/Jsonnet</a> 1.1K Star</li>
<li><a href="https://github.com/google/cel-go" target="_blank" rel="noopener">Google/CEL</a> 1K Star: 表达式语言</li>
</ul>
<hr>
<ul>
<li><a href="https://github.com/open-policy-agent/opa" target="_blank" rel="noopener">OPA/Rego</a> 6K Star: 策略语言</li>
<li><a href="https://github.com/yuin/gopher-lua" target="_blank" rel="noopener">GopherLua</a> 4.5K Star: Lua实现</li>
</ul>

      
      <span class="pagenumber">18</span>
      </article>
  
  
  
      <article >
      
        <h3>Rust 开发的编译器</h3>
        <ul>
<li><a href="https://github.com/topics/compiler?l=rust" target="_blank" rel="noopener">https://github.com/topics/compiler?l=rust</a></li>
</ul>
<hr>
<ul>
<li><a href="https://github.com/swc-project/swc" target="_blank" rel="noopener">SWC</a> 19K Star: TypeScript 编译器</li>
<li><a href="https://github.com/diem/diem/tree/main/language" target="_blank" rel="noopener">Facebook/Move</a> 16.3K Star: 区块链语言</li>
<li><a href="https://github.com/RustPython/RustPython/" target="_blank" rel="noopener">RustPython</a> 10.3K Star</li>
<li><a href="https://github.com/hyperledger-labs/solang" target="_blank" rel="noopener">solang</a> 500 Star: Solidity 编译器</li>
<li><a href="https://github.com/jolisper/ulisp" target="_blank" rel="noopener">ulisp</a> 30 Star</li>
</ul>
<hr>
<ul>
<li>目前 Rust 社区对 VM 和 Compiler 的开发比较活跃</li>
</ul>

      
      <span class="pagenumber">19</span>
      </article>
  
  
  
      <article >
      
        <h3>Go和Rust的选择</h3>
        <ul>
<li>Go编译快, GC简化开发, 运行较快, 非常适合写编译器</li>
<li>Rust编译慢, 开发繁琐, 运行时稍快(但过早释放内存影响性能), 不是编译器的最佳选择</li>
<li>如果真有死磕 Rust 语言的毅力/能力/精力, 建议去写 Rust 编译器本身</li>
</ul>
<hr>
<ul>
<li>Rust 比较适合开发长时间稳定运行的 VM 系统, 比如各种 WASM 虚拟机</li>
<li>Go 比较适合开发快速迭代, 一次完成 AOT 编译的编译器, GC 一次回收效率更高</li>
</ul>
<hr>
<ul>
<li><a href="https://www.zhihu.com/question/439945314" target="_blank" rel="noopener">esbuild为什么不用Rust，而使用了Go?</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/405160594" target="_blank" rel="noopener">写Rust的我们丢掉了什么</a></li>
</ul>

      
      <span class="pagenumber">20</span>
      </article>
  
  
  
      <article >
      
        <h2>Go衍生的语言</h2>
      
      <span class="pagenumber">21</span>
      </article>
  
  
  
      <article >
      
        <h3>Go衍生的语言</h3>
        <ul>
<li><a href="https://github.com/tinygo-org/tinygo" target="_blank" rel="noopener">TinyGo</a> 9.1K Star: 单片机环境的Go</li>
<li><a href="https://github.com/goplus/gop" target="_blank" rel="noopener">Go+</a> 7.9K Star: Go之上增加了新的特性</li>
<li><a href="https://github.com/cuelang/cue" target="_blank" rel="noopener">CUE</a> 3.2K Star: 配置语言</li>
<li><a href="https://github.com/d5/tengo" target="_blank" rel="noopener">Tengo</a> 2.5K Star: Go类似语法的脚本语言</li>
<li><a href="https://github.com/ziutek/emgo" target="_blank" rel="noopener">Emgo</a> 950 Star: 面向嵌入式环境的Go</li>
<li><a href="https://github.com/wa-lang/ugo-compiler-book" target="_blank" rel="noopener">µGo</a> 700 Star: 如何从头定制Go子集</li>
</ul>
<hr>
<ul>
<li>CUE 在配置语言领域已经形成影响力, 作者是Go团队成员, 前BCL成员</li>
<li>阿里开源的 <a href="https://github.com/oam-dev/kubevela" target="_blank" rel="noopener">KubeVela</a> 基于 CUE 构建</li>
</ul>

      
      <span class="pagenumber">22</span>
      </article>
  
  
  
      <article >
      
        <h3>TinyGo的编译器架构</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/tinygo-01.drawio.png" height="500" width="800">
</div>

      
      <span class="pagenumber">23</span>
      </article>
  
  
  
      <article >
      
        <h2>Go语法树</h2>
      
      <span class="pagenumber">24</span>
      </article>
  
  
  
      <article >
      
        <h3>FileSet 文件集模型</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch1-file-set-01.ditaa.png">
</div>
<ol>
<li>全部Go文件根据文件名排序</li>
<li>全部Go文件映射到连续的抽象内存, 每个文件对应一个区间</li>
<li><code>token.Pos</code> 表示一个指针, 0 对应 <code>token.NoPos</code> 空指针</li>
<li>这样设计的目的是为了压缩和性能, 通过一个 uint32 可以映射到文件位置</li>
</ol>

      
      <span class="pagenumber">25</span>
      </article>
  
  
  
      <article >
      
        <h3>全部的 Token 类型</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch1-token-01.png" height="500" width="900">
</div>

      
      <span class="pagenumber">26</span>
      </article>
  
  
  
      <article >
      
        <h3>表达式的语法树</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch3-expr-01.png" height="500" width="900">
</div>
<figcaption>1+2*3</figcaption>
      
      <span class="pagenumber">27</span>
      </article>
  
  
  
      <article >
      
        <h3>语法解析器接口</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch4-file-struct-01.png" height="500" width="900">
</div>
<figcaption>parser.ParseDir, parser.ParseFile</figcaption>
      
      <span class="pagenumber">28</span>
      </article>
  
  
  
      <article >
      
        <h3>方法声明的语法树结构</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch6-func-decl-01.png" height="500" width="900">
</div>
<figcaption>func (p *xType) Hello(arg1, arg2 int) (bool, error)</figcaption>
      
      <span class="pagenumber">29</span>
      </article>
  
  
  
      <article >
      
        <h2>Go类型系统</h2>
      
      <span class="pagenumber">30</span>
      </article>
  
  
  
      <article >
      
        <h3>Scope 词法域 - 01</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch12-go-types-scope-01.uml.png" height="500" width="900">
</div>
<figcaption>builtin -&gt; package -&gt; file -&gt; func</figcaption>
      
      <span class="pagenumber">31</span>
      </article>
  
  
  
      <article >
      
        <h3>Scope 词法域 - 02</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch12-go-types-scope-02.uml.png" height="500" width="900">
</div>
<figcaption>func -&gt; args -&gt; block</figcaption>
      
      <span class="pagenumber">32</span>
      </article>
  
  
  
      <article >
      
        <h3>Scope 词法域 - 03</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ch12-scope-01.png" height="500" width="900">
</div>
<figcaption>特殊的地方: Pkg 内 File 之间的命名实体可见(但不包含 import)</figcaption>
      
      <span class="pagenumber">33</span>
      </article>
  
  
  
      <article >
      
        <h3>Go类型检查</h3>
        <ul>
<li>bool/int/float/string/slice/struct/interface 排序</li>
<li>遍历AST, 判断 赋值/函数参数/返回值/表达式 类型匹配</li>
</ul>

  <div class="code" >
<pre><span num="15">func main() {</span>
<span num="16">    fset := token.NewFileSet()</span>
<span num="17">    f, err := parser.ParseFile(fset, &#34;hello.go&#34;, src, parser.AllErrors)</span>
<span num="18">    if err != nil {</span>
<span num="19">        log.Fatal(err)</span>
<span num="20">    }</span>
<span num="21">    <b>pkg, err := new(types.Config).Check(&#34;hello.go&#34;, fset, []*ast.File{f}, nil)</b></span>
<span num="22">    if err != nil {</span>
<span num="23">        log.Fatal(err)</span>
<span num="24">    }</span>
<span num="25">    _ = pkg</span>
<span num="26">}</span>
<span num="27"></span>
<span num="28">const src = `package main</span>
<span num="29">func main() {</span>
<span num="30">    <b>var _ = &#34;a&#34; &#43; 1</b></span>
<span num="31">}</span>
<span num="32">`</span>
</pre>
</div>

      
      <span class="pagenumber">34</span>
      </article>
  
  
  
      <article >
      
        <h3>Go类型信息</h3>
        <ul>
<li><code>go/types.Config.Check</code> 可为 AST 每个表达式节点标注类型信息</li>
</ul>

  <div class="code" >
<pre><span num="11">func main() {</span>
<span num="12">    fset := token.NewFileSet()</span>
<span num="13">    f, err := parser.ParseFile(fset, &#34;hello.go&#34;, src, parser.AllErrors)</span>
<span num="14">    if err != nil {</span>
<span num="15">        log.Fatal(err)</span>
<span num="16">    }</span>
<span num="17">    info := &amp;types.Info{</span>
<span num="18">        <b>Types:  make(map[ast.Expr]types.TypeAndValue),</b></span>
<span num="19">        <b>Defs:   make(map[*ast.Ident]types.Object),</b></span>
<span num="20">        <b>Uses:   make(map[*ast.Ident]types.Object),</b></span>
<span num="21">        <b>Scopes: make(map[ast.Node]*types.Scope),</b></span>
<span num="22">    }</span>
<span num="23">    conf := types.Config{Importer: nil}</span>
<span num="24">    <b>pkg, err := conf.Check(&#34;hello.go&#34;, fset, []*ast.File{f}, info)</b></span>
<span num="25">    if err != nil {</span>
<span num="26">        log.Fatal(err)</span>
<span num="27">    }</span>
<span num="28">    _ = pkg</span>
<span num="29">}</span>
</pre>
</div>

      
      <span class="pagenumber">35</span>
      </article>
  
  
  
      <article >
      
        <h2>SSA和LLVM</h2>
      
      <span class="pagenumber">36</span>
      </article>
  
  
  
      <article >
      
        <h3>SSA 基本结构</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ssa-arch-01.png" height="300" width="1000">
</div>
<ul>
<li>模块内部有全局变量和全局函数</li>
<li>函数内部有单层的 Block 列表组成(由一个Label定义)</li>
<li>每个 Block 内由单层的 指令列表组成</li>
<li>每个 Block 结尾必须跳转到其他 Block, 最后一个 Block 返回</li>
<li>每个虚拟寄存器只能被初始化一次</li>
</ul>

      
      <span class="pagenumber">37</span>
      </article>
  
  
  
      <article >
      
        <h3>Go AST 到 Go SSA - 01</h3>
        <ul>
<li>Go SSA 和  LLVM-IR 并不完全等价</li>
<li>Go SSA 抽象层次更高, 同时 SSA 只涉及语句, 不含类型和结构拆分</li>
</ul>

  <div class="code" >
<pre><span num="13">func main() {</span>
<span num="14">    fset := token.NewFileSet()</span>
<span num="15">    f, _ := parser.ParseFile(fset, &#34;hello.go&#34;, src, parser.AllErrors)</span>
<span num="16"></span>
<span num="17">    info := &amp;types.Info{}</span>
<span num="18">    conf := types.Config{Importer: nil}</span>
<span num="19">    <b>pkg, _ := conf.Check(&#34;hello.go&#34;, fset, []*ast.File{f}, info)</b></span>
<span num="20"></span>
<span num="21">    <b>var ssaProg = ssa.NewProgram(fset, ssa.SanityCheckFunctions)</b></span>
<span num="22">    <b>var ssaPkg = ssaProg.CreatePackage(pkg, []*ast.File{f}, info, true)</b></span>
<span num="23"></span>
<span num="24">    <b>ssaPkg.Build()</b></span>
<span num="25"></span>
<span num="26">    ssaPkg.WriteTo(os.Stdout)</span>
<span num="27">    <b>ssaPkg.Func(&#34;init&#34;).WriteTo(os.Stdout)</b></span>
<span num="28">    <b>ssaPkg.Func(&#34;main&#34;).WriteTo(os.Stdout)</b></span>
<span num="29">}</span>
</pre>
</div>

      
      <span class="pagenumber">38</span>
      </article>
  
  
  
      <article >
      
        <h3>Go AST 到 Go SSA - 02</h3>
        
  <div class="code" >
<pre><span num="31">const src = `</span>
<span num="32">package main</span>
<span num="33"></span>
<span num="34">var s = &#34;hello ssa&#34;</span>
<span num="35"></span>
<span num="36">func main() {</span>
<span num="37">    for i := 0; i &lt; 3; i&#43;&#43; {</span>
<span num="38">        println(s)</span>
<span num="39">    }</span>
<span num="40">}</span>
<span num="41">`</span>
</pre>
</div>

      
      <span class="pagenumber">39</span>
      </article>
  
  
  
      <article >
      
        <h3>Go AST 到 Go SSA - 03</h3>
        
  <div class="code" >
<pre><span num="1">package hello.go:</span>
<span num="2">  <b>func  init       func()</b></span>
<span num="3">  var   init$guard bool</span>
<span num="4">  <b>func  main       func()</b></span>
<span num="5"># Name: hello.go.main</span>
<span num="6"># Package: hello.go</span>
<span num="7"># Location: hello.go:4:6</span>
<span num="8"><b>func main():</b></span>
<span num="9">0:                                                                entry P:0 S:1</span>
<span num="10">        <b>jump 3</b></span>
<span num="11">1:                                                             for.body P:1 S:1</span>
<span num="12">        t0 = println(&#34;hello ssa -- chai...&#34;:string)                          ()</span>
<span num="13">        t1 = t2 &#43; 1:int                                                     int</span>
<span num="14">        <b>jump 3</b></span>
<span num="15">2:                                                             for.done P:1 S:0</span>
<span num="16">        <b>return</b></span>
<span num="17">3:                                                             for.loop P:2 S:2</span>
<span num="18">        t2 = phi [0: 0:int, 1: t1] #i                                       int</span>
<span num="19">        t3 = t2 &lt; 3:int                                                    bool</span>
<span num="20">        <b>if t3 goto 1 else 2</b></span>
</pre>
</div>

      
      <span class="pagenumber">40</span>
      </article>
  
  
  
      <article >
      
        <h3>Go SSA 的执行和再编译</h3>
        <ul>
<li>SSA 可以被解释执行: <a href="https://github.com/golang/tools/blob/master/go/ssa/interp/interp.go" target="_blank" rel="noopener">go/ssa/interp/interp.go</a></li>
<li>SSA 可以被翻译到 LLVM-IR: <a href="https://github.com/tinygo-org/tinygo/blob/release/compiler/compiler.go" target="_blank" rel="noopener">tinygo/compiler/compiler.go</a></li>
</ul>

      
      <span class="pagenumber">41</span>
      </article>
  
  
  
      <article >
      
        <h2>µGo案例</h2>
      
      <span class="pagenumber">42</span>
      </article>
  
  
  
      <article >
      
        <h3>为什么是 Go ?</h3>
        <ul>
<li>有人曾说 Shell 也能开发 Docker, 因此 Go 语言也不怎么样...</li>
</ul>
<hr>
<ul>
<li>Go 语言够简单, 25 个关键字</li>
<li>Go 语言的 <code>go/*</code> 包太好用</li>
<li>少是指数级的多 (Less is exponentially more)</li>
<li>因此 Go 社区诞生了很多衍生的定制语言</li>
</ul>
<hr>
<ul>
<li>未来 10 年, 国内的 Gopher 可以 Go 的更远</li>
</ul>

      
      <span class="pagenumber">43</span>
      </article>
  
  
  
      <article >
      
        <h3>µGo 例子</h3>
        <p>µGo 是 Go 语言的子集(不含标准库部分), 可以直接作为Go代码编译执行.</p>

  <div class="code" >
<pre><span num="3">func main() {</span>
<span num="4">    for n := 2; n &lt;= 30; n = n &#43; 1 {</span>
<span num="5">        var isPrime int = 1</span>
<span num="6">        for i := 2; i*i &lt;= n; i = i &#43; 1 {</span>
<span num="7">            if x := n % i; x == 0 {</span>
<span num="8">                isPrime = 0</span>
<span num="9">            }</span>
<span num="10">        }</span>
<span num="11">        if isPrime != 0 {</span>
<span num="12">            println(n)</span>
<span num="13">        }</span>
<span num="14">    }</span>
<span num="15">}</span>
</pre>
</div>
<ul>
<li>安装: <code>go get github.com/wa-lang/ugo</code></li>
<li>执行: <code>ugo run hello.ugo</code></li>
</ul>

      
      <span class="pagenumber">44</span>
      </article>
  
  
  
      <article >
      
        <h3>µGo 架构</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/ugo-arch.drawio.png" height="500" width="900">
</div>

      
      <span class="pagenumber">45</span>
      </article>
  
  
  
      <article >
      
        <h2>参考链接</h2>
      
      <span class="pagenumber">46</span>
      </article>
  
  
  
      <article >
      
        <h3>参考链接</h3>
        <ul>
<li><a href="https://www.sigbus.info/compilerbook" target="_blank" rel="noopener">https://www.sigbus.info/compilerbook</a></li>
<li><a href="http://cm.bell-labs.co/who/ken/trust.html" target="_blank" rel="noopener">Reflections on Trusting Trust - by Ken Thompson</a></li>
</ul>
<hr>
<ul>
<li><a href="https://github.com/wa-lang/ugo-compiler-book" target="_blank" rel="noopener">《µGo语言实现(从头开发一个迷你Go语言编译器)》</a></li>
<li><a href="https://github.com/chai2010/go-ast-book" target="_blank" rel="noopener">《Go语法树入门——开启自制编程语言和编译器之旅》</a></li>
</ul>

<div class="image">
  <img src="go-compiler-intro/images/mybooks-03.drawio.png" height="350" width="600">
</div>

      
      <span class="pagenumber">47</span>
      </article>
  
  
  
      <article >
      
        <h3>感谢 Ian 推荐序</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/go-talks-2014-compiling-ian.jpg">
</div>

      
      <span class="pagenumber">48</span>
      </article>
  
  
  
      <article >
      
        <h3>感谢 Ian 推荐序</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/preface-ian.png">
</div>

      
      <span class="pagenumber">49</span>
      </article>
  
  
  
      <article >
      
        <h3>感谢 许大 (Go 和 Go&#43; 的全部工作)</h3>
        
<div class="image">
  <img src="go-compiler-intro/images/xu-gobook.jpg" height="500" width="900">
</div>

      
      <span class="pagenumber">50</span>
      </article>
  
  
  
      <article >
      
        <h2>Q&amp;A</h2>
      
      <span class="pagenumber">51</span>
      </article>
  
  

      <article>
        <h3>Thank you</h3>
        
          <div class="presenter">
            
  
  <p>
    chai2010
  </p>
  
<p class="link"><a href="mailto:chaishushan@gmail.com" target="_blank">chaishushan@gmail.com</a></p><p class="link"><a href="https://github.com/wa-lang/ugo-compiler-book" target="_blank">https://github.com/wa-lang/ugo-compiler-book</a></p>
          </div>
        
          <div class="presenter">
            
  
  <p>
    
  </p>
  

          </div>
        
      </article>

    </section>

    <div id="help">
      Use the left and right arrow keys or click the left and right
      edges of the page to navigate between slides.<br>
      (Press 'H' or navigate to hide this message.)
    </div>

    

    <script>
      (function() {
        
        if (window["location"] && window["location"]["hostname"] == "talks.golang.org") {
          var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
          ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
          var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
        }
      })();
    </script>
  </body>
</html>